//
//  PropertiesExample.swift
//  SwiftCode
//
//  Created by yuhus on 2023/6/5.
// 

import Foundation

/*
 
 1. 属性包装器不支持局部变量
 2. 初始化的标签必须是 wrappedValue
 3. 如果初始化方法中的wrappedValue省略为_，就必须在初始化中赋值
 4. 必须包含非静态属性 wrappedValue

 */
final class PropertiesExample: ListViewController {
  deinit {
    print(#function)
  }
  
  override func getItemCount() -> Int {
    data.count
  }
  
  override func getItem(_ indexPath: IndexPath) -> Item {
    data[indexPath.row]
  }
  
  private lazy var data: [Item] = [
    .init(title: "延时加载存储属性", description: "1. 构造结束；2. 复杂计算", action: lazyStoredProperties),
    .init(title: "计算属性", description: "可用选 setter，只读计算属性只有 getter", action: computedPropertiesTest),
    .init(title: "属性包装器", description: "设置被包装属性的初始值", action: setWrappedValue),
    .init(title: "属性包装器", description: "从属性包装器中呈现一个值", action: getProjectedValue),
    .init(title: "类型属性", description: "关键字 `class` 来支持子类对父类的实现进行重写", action: typeProperties),
    .init(title: "属性包装器", description: "包装器的属性不执行 didSet 方法", action: doNotExecuteSetter),
    .init(title: "属性包装器", description: "多个包装器并排（不建议） @ZPrint @RangeLimit", action: multiParallel),
  ]
}

private class DataImporter {
  /*
   DataImporter 是一个从外部文件导入数据的类。 假设该类需要花费大量时间来初始化。
   */
  var filename = "data.txt"
  // DataImporter 类将在此处提供数据导入功能
}

private class DataManager {
  lazy var importer = DataImporter()
  var data: [String] = []
  // DataManager 类将在此处提供数据管理功能
}

private func lazyStoredProperties() {
  let manager = DataManager()
  manager.data.append("Some data")
  manager.data.append("Some more data")
  // DataImporter 实例的 importer 属性还没有被创建
}

private struct Point { var x = 0.0, y = 0.0 }

private struct Size { var width = 0.0, height = 0.0 }
/// 简洁矩形
private struct CompactRect {
  var origin = Point()
  var size = Size()
  var center: Point {
    get {
      Point(x: origin.x + (size.width / 2),
            y: origin.y + (size.height / 2))
    }
    set {
      origin.x = newValue.x - (size.width / 2)
      origin.y = newValue.y - (size.height / 2)
    }
  }
}

/// 只读计算属性没有 getter
private func computedPropertiesTest() {
  var square = CompactRect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
  _ = square.center
  // initialSquareCenter 位于（5.0， 5.0）
  square.center = Point(x: 15.0, y: 15.0)
  print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
  // 打印“square.origin is now at (10.0, 10.0)”
}

@propertyWrapper
private struct SmallNumber {
  private var maximum: Int
  private var number: Int
  
  var wrappedValue: Int {
    get { return number }
    set { number = min(newValue, maximum) }
  }
  
  init() {
    self.maximum = 12
    self.number = 0
  }
  
  init(wrappedValue: Int) {
    maximum = 12
    number = min(wrappedValue, maximum)
  }
  
  init(wrappedValue: Int, maximum: Int) {
    self.maximum = maximum
    number = min(wrappedValue, maximum)
  }
}

private func setWrappedValue() {
  print("使用 init() 构造器")
  struct ZeroRectangle {
    @SmallNumber var height: Int
    @SmallNumber var width: Int
  }
  
  let zeroRectangle = ZeroRectangle()
  print(zeroRectangle.height, zeroRectangle.width)
  // 打印 "0 0"
  
  print("使用 init(wrappedValue:) 构造器")
  struct UnitRectangle { // 单位矩形
    @SmallNumber var height: Int = 1
    @SmallNumber var width: Int = 1
  }
  
  let unitRectangle = UnitRectangle()
  print(unitRectangle.height, unitRectangle.width)
  // 打印 "1 1"
  
  print("使用 init(wrappedValue:maximum:) 构造器")
  struct NarrowRectangle { // 狭小矩形
    @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
    @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
  }
  
  var narrowRectangle = NarrowRectangle()
  print(narrowRectangle.height, narrowRectangle.width)
  // 打印 "2 3"
  
  narrowRectangle.height = 100
  narrowRectangle.width = 100
  print(narrowRectangle.height, narrowRectangle.width)
  // 打印 "5 4"
  
  print("赋值视为 wrappedValue 参数")
  struct MixedRectangle {
    @SmallNumber var height: Int = 1
    @SmallNumber(maximum: 9) var width: Int = 2
  }
  
  var mixedRectangle = MixedRectangle()
  print(mixedRectangle.height)
  // 打印 "1"
  
  mixedRectangle.height = 20
  print(mixedRectangle.height)
  // 打印 "12"
}

@propertyWrapper
/// 呈现值可以是任何类型，也可以返回自身来暴露出包装器的实例（Alamofire 中 `Protected<T>`）
private struct ProjectedNumber {
  private var number: Int
  private(set) var projectedValue: Bool
  
  var wrappedValue: Int {
    get { return number }
    set {
      if newValue > 12 {
        number = 12
        projectedValue = true
      } else {
        number = newValue
        projectedValue = false
      }
    }
  }
  
  init() {
    self.number = 0
    self.projectedValue = false
  }
}

private func getProjectedValue() {
  print("数值是否被调整过")
  struct SomeStructure {
    @ProjectedNumber var someNumber: Int
  }
  
  var someStructure = SomeStructure()
  someStructure.someNumber = 4
  print(someStructure.$someNumber)
  // Prints "false"
  
  someStructure.someNumber = 55
  print(someStructure.$someNumber)
  // Prints "true"
}



private func typeProperties() {
  // 使用 static 关键字定义类型属性。 对于类类型的计算类型属性，您可以使用 class 关键字来允许子类覆盖超类的实现
  class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
      return 27
    }
    class var overrideableComputedTypeProperty: Int {
      return 107
    }
  }
  
  class SomeSubclass: SomeClass {
    class override var overrideableComputedTypeProperty: Int {
      return 207
    }
  }
  
  print("SomeClass")
  print(SomeClass.storedTypeProperty)
  print(SomeClass.computedTypeProperty)
  print(SomeClass.overrideableComputedTypeProperty)
  print("SomeSubclass")
  print(SomeSubclass.storedTypeProperty)
  print(SomeSubclass.computedTypeProperty)
  print(SomeSubclass.overrideableComputedTypeProperty)
}

@propertyWrapper
private struct First<C> {
  var wrappedValue: C
  
  init(wrappedValue: C) {
    Timber.d("wrappedValue", wrappedValue)
    print(Self.self, #function)
    self.wrappedValue = wrappedValue
  }
}

@propertyWrapper
private struct Second<T> {
  var wrappedValue: T
  
  init(wrappedValue: T) {
    print(Self.self, #function)
    self.wrappedValue = wrappedValue
  }
}

@propertyWrapper
private struct RangeLimit<C: Comparable> {
  private var value: C
  private var max: C
  private var min: C
  
  var wrappedValue: C {
    get { value }
    set { value = min < newValue ? max > newValue ? newValue : max : min }
  }
  
  init(wrappedValue: C, min: C, max: C) {
    print(Self.self, #function)
    self.min = min
    self.max = max
    self.value = wrappedValue
  }
}

@propertyWrapper
private struct ZPrint<T> {
  private var value: T
  
  var wrappedValue: T {
    get { value }
    set { value = newValue }
  }
  init(wrappedValue: T) {
    print(Self.self, #function)
    self.value = wrappedValue
  }
}

@propertyWrapper
private struct PrintLimit<C: Comparable> {
  private var value: ZPrint<RangeLimit<C>>
  
  var wrappedValue: C {
    get {
      return value.wrappedValue.wrappedValue
    }
    set {
      value.wrappedValue.wrappedValue = newValue
    }
  }
  
  init(wrappedValue: C, min: C, max: C) {
    self.value = ZPrint(wrappedValue: RangeLimit(wrappedValue: wrappedValue, min: min, max: max))
  }
}

/// 包装器的属性不执行 didSet 方法
private func doNotExecuteSetter() {
  struct MultiWrapper {
    @RangeLimit(wrappedValue: "A", min: "B", max: "C") var abc
  }
  
  print(#"初始化 (wrappedValue: "A", min: "B", max: "C")"#)
  var multi = MultiWrapper()
  print(multi.abc)
  
  print("赋值 = A")
  multi.abc = "A"
  print(multi.abc)
}

/// 执行的顺序是从内到外的，从离属性近的开始执行(即从右到左，由下而上的)
private func multiParallel() {
  struct MultiWrapper {
    // 编译错误: Type annotation missing in pattern
    // @ZPrint @RangeLimit(wrappedValue: "A", min: "B", max: "C") var abc
    
    @ZPrint
    @RangeLimit(min: "B", max: "C") var abc = "A"
  }
  
  print(#"初始化 (wrappedValue: "A", min: "B", max: "C")"#)
  _ = MultiWrapper()
  // ZPrint<RangeLimit<String>> init(wrappedValue:)
}
